/* Copyright 2017, 2018, 2019, 2020 Gabriel Czernikier
 *
 * This file is part of Côtehaus.
 * Côtehaus is free software: you can redistribute it and/or modify
 * it under the terms of one of the following:
 * 1. The same dual license as that of Côtehaus itself, of which individual licenses are
 * the MIT License and the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 2. The MIT License.
 * 3. The GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * Côtehaus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * MIT License and the GNU General Public License for more details.
 * You should have received a copy of the MIT License and the GNU General Public License
 * along with Côtehaus.  If not, see <https://opensource.org/licenses/MIT> and <http://www.gnu.org/licenses/>.
 */
/*
 * With regard on memory deallocation, it's arguable how this program neglect to free most of its dynamically allocated memmory.
 * Although the habit of disposing memory is good and healthy, non-conformance with that is acceptable.
 * Considering the "batch" nature of this program, let it be authoritative for the sake of validating these lines, what's said in the manual for Bison 2.4.1, section 3.7.7 (as well as for Bison 3.0.x, section 3.7.6),
 * Freeing Discarded Symbols (node Destructor Decl of info doc): "When [...] convey heap based information, this memory is lost. While this behavior can be tolerable for batch...".
 * Wherever it is discovered a program termination from which an invariance can be acknowledged that memory is left retained, and so a job on disposal incompletely done as for leaving uncleaned "leftovers", it is marked by a message that includes the words "clutter" or "cluttering" as part of it. Neither that it harms nor that the intention is a fixing, however.
 */
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "composer.h"
#include "parse_file.h"
#include "types.h"

// Imports functions
void build_map_list();  // map_list.c
void pack_map_list();  // map_list.c
void build_header();  // header.c
void pack_header();  // header.c

struct thing_list_st {
	/*TODO wchar_t --> */char *thing;
	struct list_head thing_list;
};

// TODO wchar_t interface to GNU C library getopt.
wchar_t *getopt_wc(int argc, char *const *argv, wchar_t *options) {
	int aflag = 0;
	int bflag = 0;
	char *cvalue = NULL;
	int index;
	int c;

	opterr = 0;


	while ((c = getopt (argc, argv, "abc:")) != -1)
		switch (c)
			{
			case 'a':
				aflag = 1;
				break;
			case 'b':
				bflag = 1;
				break;
			case 'c':
				cvalue = optarg;
				break;
			case '?':
				if (optopt == 'c')
					fprintf (stderr, "Option -%c requires an argument.\n", optopt);
				else if (isprint (optopt))
					fprintf (stderr, "Unknown option `-%c'.\n", optopt);
				else
					fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
				return 1;
			default:
				abort ();
			}


	printf ("aflag = %d, bflag = %d, cvalue = %s\n", aflag, bflag, cvalue);

	for (index = optind; index < argc; index++)
		printf ("Non-option argument %s\n", argv[index]);
	return 0;
}

void derive_itemset_2(char *path, struct list_head itemset);

struct list_head derive_itemset(/*TODO wchar_t --> */ char *path) {
	LIST_HEAD(itemset);
	derive_itemset_2(path, itemset);
	return itemset;
}

void derive_itemset_2(/*TODO wchar_t --> */char *path, struct list_head itemset) {
	if((DIR *dir = opendir(path))==NULL) {
		// take apart the case of ENOTDIR as an expectable (handleable) possibility and recover the error by turning path into a regular file to be processed. (https://www.gnu.org/software/libc/manual/html_node/File-Name-Errors.html)
		if(errno!=ENOTDIR) {
			perror("opendir");
			exit(EXIT_FAILURE);
		}
		struct thing_list_st *item = (struct thing_list_st*)malloc(sizeof(struct thing_list_st));
		item->thing = (char *)malloc(sizeof(char)*(strlen(path)+strlen(entry->d_name)+2/*'/'+'\0'*/));
		strcpy(item->thing, path);
		strcat(item->thing, "/"); // FIXME It's not well resolved but for all ASCII-based encodings. https://www.gnu.org/software/libc/manual/html_node/Extended-Char-Intro.html: "All of the ASCII-based character sets fulfill one requirement: they are "filesystem safe." This means that the character '/' is used in the encoding only to represent itself."
		strcat(item->thing, entry->d_name);
		list_add_tail(&item->thing_list, &itemset);
		return;
	}

	for(errno=0; struct dirent *entry = readdir(dir); errno=0) {
		char **tmp = &entry->d_name;
		size_t len = mbsrtowc(NULL, tmp, 0, NULL);
		wchar_t *entryname = (wchar_t*)malloc(sizeof(wchar_t)*(len+1));
		mbsrtowc(entryname, tmp = &entry->d_name, len+1, NULL);
		if(! ( wcscmp(L".", entryname) && wcscmp(L"..", entryname) ) )
			continue;
		// TODO recurse subdirectories
	}

	if(errno) {
		perror("readdir");
		exit(EXIT_FAILURE);
	}

}

int main(int argc, char **argv) {
	if(argc<2) {
		fprintf(stderr, "Program usage: %s <more options...>", argv[0]);
		exit(EXIT_FAILURE);
	}
	
	struct thing_list_st *pathname;
	list_foreach_entry(pathname, struct thing_list_st, thing_list, &derive_itemset(getopt_wc(L"srcpath", argc, argv)))
		parse_file(pathname, false);
	/* Now go with the pseudo source code form of api exposed information, like what can be obtained by running fetch-api-doc.sh and doc2jstub.pl. */ 
	list_foreach_entry(pathname, struct thing_list_st, thing_list, &derive_itemset(getopt_wc(L"libpath", argc, argv)))
		parse_file(pathname, true);
	resolve_types();
	build_ostr_id_and_pack_str_dt();
	build_otype_id();
	build_otype_list();
	build_oproto_id();
	build_omethod_id();
	build_oclass_def();
	build_header();
	build_map_list();
	align_bounds();
	pack_ostr_id_ary();
	pack_otype_id();
	pack_otype_list();
	pack_oproto_id();
	pack_omethod_id();
	pack_oclass_def();
	pack_map_list();
	pack_header();
	FILE *fw = fopen("classes.dex", "wb");
	for(int i=1; i!=CH_UP_BOUNDS_SZ; i++) {
		fwrite(buffer[i], 1, buf_len[i], fw);
	}
	fclose(fw);
	exit(EXIT_SUCCESS);
	return 0;
}
